package com.cxd.performance.service.impl;


import com.cxd.performance.domain.MessageDomain;
import com.cxd.performance.enums.MailCodeEnum;
import com.cxd.performance.exception.BusinessException;
import com.cxd.performance.service.MailSenderService;
import com.cxd.performance.utils.BaseStringUtils;
import com.cxd.performance.utils.RegexUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.stereotype.Service;

import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
import java.io.File;
import java.util.Arrays;
/**
 * 待开发:
 *
 *  发送失败
 *
 *         因为各种原因，总会有邮件发送失败的情况，比如：邮件发送过于频繁、网络异常等。在出现这种情况的时候，我们一般会考虑重新重试发送邮件，会分为以下几个步骤来实现：
 *
 *         1、接收到发送邮件请求，首先记录请求并且入库。
 *         2、调用邮件发送接口发送邮件，并且将发送结果记录入库。
 *         3、启动定时系统扫描时间段内，未发送成功并且重试次数小于3次的邮件，进行再次发送
 *
 *  异步发送
 *
 *         很多时候邮件发送并不是我们主业务必须关注的结果，比如通知类、提醒类的业务可以允许延时或者失败。
 *         这个时候可以采用异步的方式来发送邮件，加快主交易执行速度，
 *         在实际项目中可以采用MQ发送邮件相关参数，监听到消息队列之后启动发送邮件
 */

/**
 * Author: Calvin
 * Date: 2019-08-30 8:40
 * Description: 邮件发送实现类
 */
@Slf4j
@Service
public class MailSenderServiceImpl implements MailSenderService {

    @Autowired
    private JavaMailSender javaMailSender;

    @Value("${mail.fromMail.addr}")
    public String from ;

    static {
        System.setProperty("mail.mime.splitlongparameters","false");
        System.setProperty("mail.mime.charset","UTF-8");
    }

    @Override
    public void sendSimpleMail(MessageDomain messageDomain) {

        //参数日志记录
        printLog(messageDomain);

        //数据校验
        checkData(messageDomain);

        //组装参数
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(messageDomain.getTo());
        message.setSubject(messageDomain.getSubject());
        message.setText(messageDomain.getContent());

        //发送邮件
        try {
            javaMailSender.send(message);
            log.info("[简单邮件],发送成功");
        }catch (Exception e) {
            log.error("[简单邮件],发送时发生异常!", e);
        }

    }

    @Override
    public void sendHtmlMail(MessageDomain messageDomain) {

        //参数日志记录
        printLog(messageDomain);

        //数据校验
        checkData(messageDomain);

        //组装参数
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {

            MimeMessageHelper helper = getMimeMessageHelper(messageDomain, mimeMessage);
            javaMailSender.send(mimeMessage);
            log.info("[html邮件],发送成功");
        } catch (MessagingException e) {
            log.error("[html邮件],发送时出现异常!", e);
        }

    }

    @Override
    public void sendAttachmentsMail(MessageDomain messageDomain) {

        //参数日志打印
        printLog(messageDomain);

        //参数校验
        checkData(messageDomain);
        String filePath = messageDomain.getFilePath();
        if (BaseStringUtils.isEmpty(filePath)) {
            throw new BusinessException(MailCodeEnum.MAIL_FILEPATH_NONULL);
        }

        //参数组装
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();
        try {
            MimeMessageHelper helper = getMimeMessageHelper(messageDomain, mimeMessage);

            FileSystemResource file = new FileSystemResource(new File(filePath));
            String fileName = file.getFilename();
            helper.addAttachment(fileName, file);
            javaMailSender.send(mimeMessage);
            log.info("[附件邮件],发送成功");
        }catch (Exception e) {
            log.error("[附件邮件],发送时发生异常!", e);
        }
    }

    @Override
    public void sendInlineResourceMail(MessageDomain messageDomain) {

        //参数日志打印
        printLog(messageDomain);

        //参数校验
        checkData(messageDomain);
        String srcPath = messageDomain.getSrcPath();
        String srcId = messageDomain.getSrcId();
        if (BaseStringUtils.isEmpty(srcPath)) {
            throw new BusinessException(MailCodeEnum.MAIL_FILEPATH_NONULL);
        }
        if (BaseStringUtils.isEmpty(srcId)) {
            throw new BusinessException(MailCodeEnum.MAIL_SRCID_NONULL);
        }

        //参数组装
        MimeMessage mimeMessage = javaMailSender.createMimeMessage();

        try {
            MimeMessageHelper helper = getMimeMessageHelper(messageDomain, mimeMessage);

            FileSystemResource res = new FileSystemResource(new File(srcPath));
            helper.addInline(srcId,res);

            javaMailSender.send(mimeMessage);
            log.info("[静态资源(图片)邮件],发送成功");
        }catch (Exception e) {
            log.error("[静态资源(图片)邮件],发送失败!",e);
        }
    }

    private MimeMessageHelper getMimeMessageHelper(MessageDomain messageDomain, MimeMessage mimeMessage) throws MessagingException {
        //true表示需要创建一个multipart message
        MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);
        helper.setFrom(from);
        helper.setTo(messageDomain.getTo());
        helper.setSubject(messageDomain.getSubject());
        helper.setText(messageDomain.getContent(),true);
        return helper;
    }

    private void checkData(MessageDomain messageDomain) {
        if (null == messageDomain) {
            log.warn("send simpleMail,but messageDomain is null");
            return;
        }
        if (BaseStringUtils.isEmpty(messageDomain.getTo())) {
            throw new BusinessException(MailCodeEnum.MAIL_TO_NONULL);
        }
        Arrays.stream(messageDomain.getTo()).forEach(x -> {
            if (!RegexUtils.validateEmailFormat(x)) {
                throw new BusinessException(MailCodeEnum.MAIL_ADDR_INVALID);
            }
        });
        if (BaseStringUtils.isEmpty(messageDomain.getSubject())) {
            throw new BusinessException(MailCodeEnum.MAIL_SUBJECT_NONULL);
        }
        if (BaseStringUtils.isEmpty(messageDomain.getContent())) {
            throw new BusinessException(MailCodeEnum.MAIL_CONTENT_NONULL);
        }
    }

    private void printLog(MessageDomain messageDomain) {
        log.info("**************************************************"+"\n");
        log.info("发送邮件:");
        log.info("发件人:{}",from);
        log.info("收件人:{}",messageDomain.getTo());
        log.info("邮件主题:{}",messageDomain.getSubject());
        log.info("邮件内容:{}",messageDomain.getContent());
        log.info("\n");
        log.info("**************************************************");
    }

}
